import * as THREE from 'three';
import mapboxgl from 'mapbox-gl';
import {RGBELoader} from "three/examples/jsm/loaders/RGBELoader";

class PipelineLayer {

    constructor(id, modelOrigin) {

        this.id = id;
        this.type = 'custom';
        this.renderingMode = '3d';
        this.modelOrigin   = modelOrigin;

        var modelAltitude = 0;
        var modelRotate = [Math.PI / 2, 0, 0];

        var modelAsMercatorCoordinate = mapboxgl.MercatorCoordinate.fromLngLat(
            this.modelOrigin,
            modelAltitude
        );

        this.modelTransform = {
            translateX: modelAsMercatorCoordinate.x,
            translateY: modelAsMercatorCoordinate.y,
            translateZ: modelAsMercatorCoordinate.z,
            rotateX: modelRotate[0],
            rotateY: modelRotate[1],
            rotateZ: modelRotate[2],
            /* Since our 3D model is in real world meters, a scale transform needs to be
             * applied since the CustomLayerInterface expects units in MercatorCoordinates.
             */
            scale: modelAsMercatorCoordinate.meterInMercatorCoordinateUnits()
        };
    }

    onAdd(map, gl) {

        this.map = map;

        this.camera = new THREE.Camera();
        this.scene  = new THREE.Scene();

        this.pipelinesGroup = new THREE.Group();
        this.scene.add(this.pipelinesGroup);

        /*const axesHelper = new THREE.AxesHelper(1000);
        this.scene.add(axesHelper);*/

        this.renderer = new THREE.WebGLRenderer({
            canvas: map.getCanvas(),
            context: gl,
            antialias: true
        });

        this.renderer.shadowMap.enabled = true;
        this.renderer.autoClear = false;
        this.renderer.physicallyCorrectLights = true;
        this.renderer.outputEncoding = THREE.sRGBEncoding;

        var pmremGenerator = new THREE.PMREMGenerator(this.renderer);
        pmremGenerator.compileEquirectangularShader();

        new RGBELoader().setDataType(THREE.UnsignedByteType).load('textures/pump_station_1k.hdr', dataTexture => {

            let envMap = pmremGenerator.fromEquirectangular(dataTexture).texture;
            pmremGenerator.dispose();

            this.scene.environment = envMap;
        })

        this.rayCaster = new THREE.Raycaster();
    }

    render(gl, matrix) {
        //纹理动画
        let texture = this.object.material.map
        texture.offset.x -= 0.03;


        var rotationX = new THREE.Matrix4().makeRotationAxis(
            new THREE.Vector3(1, 0, 0),
            this.modelTransform.rotateX
        );
        var rotationY = new THREE.Matrix4().makeRotationAxis(
            new THREE.Vector3(0, 1, 0),
            this.modelTransform.rotateY
        );
        var rotationZ = new THREE.Matrix4().makeRotationAxis(
            new THREE.Vector3(0, 0, 1),
            this.modelTransform.rotateZ
        );

        var m = new THREE.Matrix4().fromArray(matrix);
        var l = new THREE.Matrix4()
            .makeTranslation(
                this.modelTransform.translateX,
                this.modelTransform.translateY,
                this.modelTransform.translateZ
            )
            .scale(
                new THREE.Vector3(
                    this.modelTransform.scale,
                    -this.modelTransform.scale,
                    this.modelTransform.scale
                )
            )
            .multiply(rotationX)
            .multiply(rotationY)
            .multiply(rotationZ);

        this.camera.projectionMatrix = m.multiply(l);
        this.renderer.resetState();
		
        this.renderer.render(this.scene, this.camera);
        this.map.triggerRepaint();
    }

    addObject(object, pos = {x: 0, y: 0, z: 0}) {
        console.log("ob",object)

        object.position.set(pos.x, pos.y, pos.z);
        this.object = object
        this.pipelinesGroup.add(object);
    }

    removeObject(object) {

        this.pipelinesGroup.remove(object);
    }

    queryRenderedFeatures(point) {

        var mouse = new THREE.Vector2();

        mouse.x = (point.x / this.map.transform.width) * 2 - 1;
        mouse.y = - (point.y / this.map.transform.height) * 2 + 1;

        let cameraInverseProjection = this.camera.projectionMatrix.invert();
        let cameraPosition = new THREE.Vector3().applyMatrix4(cameraInverseProjection);
        let mousePosition  = new THREE.Vector3(mouse.x, mouse.y, 1).applyMatrix4(cameraInverseProjection);
        let viewDirection  = mousePosition.clone().sub(cameraPosition).normalize();

        this.rayCaster.set(cameraPosition, viewDirection);

        return this.rayCaster.intersectObject(this.scene, true);
    }
}

export default PipelineLayer